import defaultConfig from '../../Config';
import { DrawConfig, RowInfo } from '../../type';
import ReadJson from '@/utils/FileUtils/ReadJson';
import ReadImage from '@/utils/FileUtils/ReadImage';
import ReadFileString from '@/utils/FileUtils/ReadFileString';
import FormatString from '@/visual/utils/ConfigUtils/FormatString';
import { calcSemilogarithmicX } from '@/visual/utils/ConfigUtils/Semilogarithmic';
import { SplitNumber } from '@/visual/utils/ConfigUtils/SplitNumber';
import WatchGradualNumber from '@/utils/WatchGradualNumber';
import WatchNumber from '@/utils/WatchNumber';
import GradualNumber, { ChangeCallBack } from '@/utils/GradualNumber';
import WatchValue from '@/utils/WatchValue';

export type WatchConfig = {
	[P in keyof DrawConfig]: WatchValue<DrawConfig[P]>;
}

/** 配置文件系统 */
export default class ConfigUtils {

	/** 配置路径 */
	private path: string = "";

	/** 配置文件数据 */
	public config: WatchConfig;

	private transitionValueChanger!: WatchValue<ChangeCallBack>;

	private transitionYChanger!: WatchValue<ChangeCallBack>;

	private transitionSplitLineChanger!: WatchValue<ChangeCallBack>;

	/** 构造函数 */
	public constructor() {
		const config = this.config = {} as any;
		const defConfig = Object.assign({}, defaultConfig);
		for (const _key in defConfig) {
			const key = _key as keyof DrawConfig;
			config[key] = new WatchValue<any>(defConfig[key]);
		}
		this.initChanger();
	}

	private initChanger() {
		const transitionValue = this.config.transitionValue;
		this.transitionValueChanger = new WatchValue(() => GradualNumber.MakeChanger(transitionValue.Value), transitionValue);

		const transitionY = this.config.transitionY;
		this.transitionYChanger = new WatchValue(() => GradualNumber.MakeChanger(transitionY.Value), transitionY);

		const transitionSplitLine = this.config.transitionSplitLine;
		this.transitionSplitLineChanger = new WatchValue(() => GradualNumber.MakeChanger(transitionSplitLine.Value), transitionSplitLine);
	}

	/** 加载配置 */
	public async Load(path: string) {
		this.path = path;
		const config = this.config;
		const readConfig = await ReadJson<any>(`${path}/config.json`);
		this.ClearTarget();
		for (const _key in readConfig) {
			const key = _key as keyof DrawConfig;
			const info = config[key];
			if (info) {
				info.Value = readConfig[key];
			}
		}
	}

	/** 清楚绑定公式 */
	private ClearTarget() {
		const config = this.config;
		for (const _key in config) {
			const key = _key as keyof DrawConfig;
			const info = config[key];
			info.ClearTarget("remove");
		}
	}

	/** 加载背景图片 */
	public async LoadBackgroundImage() {
		const { path, config } = this;
		const { backgroundImageUrl } = config;
		const getImage = async () => {
			if (backgroundImageUrl.Value) {
				try {
					return await ReadImage(`${path}/${backgroundImageUrl.Value}`);
				} catch (error) {
					return undefined;
				}
			} else {
				return undefined;
			}
		}
		const watch = new WatchValue<CanvasImageSource | undefined>(await getImage());
		backgroundImageUrl.Add("remove", () => {
			getImage().then(image => {
				watch.Value = image;
			});
		});
		return watch;
	}

	/** 加载表格数据 */
	public async LoadCSV(): Promise<string> {
		const { path, config: drawConfig } = this;
		const { charset } = drawConfig;
		return await ReadFileString(`${path}/data.csv`, charset.Value);
	}

	/** 创建数值过渡 */
	public makeValueTranstion(value: number) {
		const { config } = this;
		const { valueFrame } = config;
		return new WatchGradualNumber(value, valueFrame, this.transitionValueChanger);
	}

	/** 创建数据条Y轴过渡 */
	public makeYTranstion(value: number) {
		const { config: drawConfig } = this;
		const { yFrame } = drawConfig;
		return new WatchGradualNumber(value, yFrame, this.transitionYChanger);
	}

	/** 创建分割线透度过渡 */
	public makeSplitLineTranstion(value: number) {
		const { config: drawConfig } = this;
		const { splitLineFrame } = drawConfig;
		return new WatchGradualNumber(value, splitLineFrame, this.transitionSplitLineChanger);
	}

	/**
	 * 格式化数据条名称
	 * @param rowInfo 数据条CSV加载数据
	 */
	public makeFormatName(rowInfo: RowInfo) {
		const { config } = this;
		const { formatName } = config;
		if (formatName.Value) {
			try {
				return FormatString(formatName.Value, rowInfo);
			} catch (error) {
				return rowInfo.name;
			}
		} else {
			return rowInfo.name;
		}
	}

	/**
	 * 格式化数据条名称
	 * @param rowInfo 数据条CSV加载数据
	 */
	public makeFormatNameWatch(rowInfo: RowInfo) {
		const { config } = this;
		const { formatName } = config;
		return new WatchValue<string>(() => {
			return this.makeFormatName(rowInfo);
		}, formatName);
	}

	/**
	 * 格式化数值
	 * @param value 被格式化的数值
	 */
	public makeFormatValue(value: number) {
		const { config: drawConfig } = this;
		const { formatValue } = drawConfig;
		if (formatValue.Value) {
			try {
				return FormatString(formatValue.Value, value);
			} catch (error) {
				return value.toFixed(0);
			}
		} else {
			return value.toFixed(0);
		}
	}

	/**
	 * 格式化数值
	 * @param value 被格式化的数值
	 */
	public makeFormatValueWatch(value: WatchNumber) {
		const { config } = this;
		const { formatValue } = config;
		return new WatchValue<string>(() => {
			return this.makeFormatValue(value.Value);
		}, value, formatValue);
	}

	/**
	 * 格式化分割线数值
	 * @param value 被格式化的数值
	 */
	public makeFormatSplitValue(value: number) {
		const { config: drawConfig } = this;
		const { formatSplitValue } = drawConfig;
		if (formatSplitValue.Value) {
			try {
				return FormatString(formatSplitValue.Value, value);
			} catch (error) {
				return value.toFixed();
			}
		} else {
			return value.toFixed();
		}
	}

	/**
	 * 格式化分割线数值
	 * @param value 被格式化的数值
	 */
	public makeFormatSplitValueWatch(value: number) {
		const { config } = this;
		const { formatSplitValue } = config;
		return new WatchValue<string>(() => {
			return this.makeFormatSplitValue(value);
		}, formatSplitValue);
	}

	/**
	 * 取数据条颜色
	 * @param rowInfo 数据条CSV加载数据
	 */
	public getInfoColor(rowInfo: RowInfo) {
		return rowInfo.color;
	}

	/**
	 * 取数据条图标
	 * @param rowInfo 数据条CSV加载数据
	 * @param icon 图标路径
	 */
	public async getInfoIcon({ icon }: RowInfo) {
		const { path } = this;
		if (icon) {
			try {
				return await ReadImage(`${path}/${icon}`);
			} catch {
				return new Image();
			}
		} else {
			return new Image();
		}
	}

	/**
	 * 计算数值对应坐标宽度因数
	 * @param min 最小值
	 * @param max 最大值
	 * @param value 当前值
	 */
	public CalcAxisWidth(min: number, max: number, value: number) {
		const { config } = this;
		const { axisSemilogarithmicX } = config;
		if (axisSemilogarithmicX.Value) {
			min = calcSemilogarithmicX(min);
			max = calcSemilogarithmicX(max);
			value = calcSemilogarithmicX(value);
		}
		return (value - min) / (max - min);
	}

	/**
	 * 计算分割线
	 * @param min X轴最小值
	 * @param max X轴最大值
	 */
	public CalcSplitLine(min: number, max: number) {
		const { config } = this;
		const { splitLineCount, splitLineValue, splitLineUnit } = config
		return SplitNumber(min, max, splitLineCount.Value, splitLineValue.Value, splitLineUnit.Value);
	}
}
